
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="utf-8">
    <link rel="canonical" href="https://blog.csdn.net/LinkSLA/article/details/129547714"/>
    <meta http-equiv="content-type" content="text/html; charset=utf-8">
    <meta name="renderer" content="webkit"/>
    <meta name="force-rendering" content="webkit"/>
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/>
    <meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
    <meta name="report" content='{"spm":"1001.2101","extra":{"titAb":"t_1","tsab":"t_3","tag":"t_2"},"pid":"blog"}'>
    <meta name="referrer" content="always">
    <meta http-equiv="Cache-Control" content="no-siteapp" /><link rel="alternate" media="handheld" href="#" />
    <meta name="shenma-site-verification" content="5a59773ab8077d4a62bf469ab966a63b_1497598848">
    <meta name="applicable-device" content="pc">
    <link  href="https://g.csdnimg.cn/static/logo/favicon32.ico"  rel="shortcut icon" type="image/x-icon" />
    <title>2023版最新最全React面试题_LinkSLA的博客-CSDN博客</title>
    <script>
      (function(){ 
        var el = document.createElement("script"); 
        el.src = "https://s3a.pstatp.com/toutiao/push.js?1abfa13dfe74d72d41d83c86d240de427e7cac50c51ead53b2e79d40c7952a23ed7716d05b4a0f683a653eab3e214672511de2457e74e99286eb2c33f4428830"; 
        el.id = "ttzz"; 
        var s = document.getElementsByTagName("script")[0]; 
        s.parentNode.insertBefore(el, s);
      })(window)
    </script>
        <meta name="keywords" content="react面试题">
        <meta name="csdn-baidu-search"  content='{"autorun":true,"install":true,"keyword":"react面试题"}'>
    <meta name="description" content="受控组件：只能通过 React 修改数据或状态的组件，就是受控组件；非受控组件：与受控组件相反，如 input, textarea, select, checkbox 等组件，本身控件自己就能控制数据和状态的变更，而且 React 是不知道这些变更的；那么如何将非受控组件改为受控组件呢？return (&lt;&gt;&lt;/&gt;上面代码中，输入框和 checkbox 的变化，均是经过了 React 来操作的，在数据变更时，React 是能够知道的。">
        <link rel="stylesheet" type="text/css" href="https://csdnimg.cn/release/blogv2/dist/pc/css/detail_enter-763d91c8fb.min.css">
    <script type="application/ld+json">{"@context":"https://ziyuan.baidu.com/contexts/cambrian.jsonld","@id":"https://blog.csdn.net/LinkSLA/article/details/129547714","appid":"1638831770136827","pubDate":"2023-03-15T10:40:03","title":"2023版最新最全React面试题_LinkSLA的博客-CSDN博客","upDate":"2023-03-15T10:40:03"}</script>
        <link rel="stylesheet" type="text/css" href="https://csdnimg.cn/release/blogv2/dist/pc/themesSkin/skin-number/skin-number-2c93789924.min.css">
    <script src="https://csdnimg.cn/public/common/libs/jquery/jquery-1.9.1.min.js" type="text/javascript"></script>
    <script type="text/javascript">
        var isCorporate = false;//注释删除enterprise
        var username =  "LinkSLA";
        var skinImg = "white";
        var blog_address = "https://blog.csdn.net/LinkSLA";
        var currentUserName = "weixin_52215647";
        var isOwner = false;
        var loginUrl = "http://passport.csdn.net/account/login?from=https://blog.csdn.net/LinkSLA/article/details/129547714";
        var blogUrl = "https://blog.csdn.net/";
        var avatar = "https://profile.csdnimg.cn/1/6/1/1_linksla";
        var articleTitle = "2023版最新最全React面试题";
        var articleDesc = "受控组件：只能通过 React 修改数据或状态的组件，就是受控组件；非受控组件：与受控组件相反，如 input, textarea, select, checkbox 等组件，本身控件自己就能控制数据和状态的变更，而且 React 是不知道这些变更的；那么如何将非受控组件改为受控组件呢？return (&lt;&gt;&lt;\/&gt;上面代码中，输入框和 checkbox 的变化，均是经过了 React 来操作的，在数据变更时，React 是能够知道的。";
        var articleTitles = "2023版最新最全React面试题_LinkSLA的博客-CSDN博客";
        var nickName = "LinkSLA";
        var articleDetailUrl = "https://blog.csdn.net/LinkSLA/article/details/129547714";
        if(window.location.host.split('.').length == 3) {
            blog_address = blogUrl + username;
        }
        var skinStatus = "White";
        var blogStaticHost = "https://csdnimg.cn/release/blogv2/"
        var mallTestStyle = "control"
    </script>
    <script src="https://g.csdnimg.cn/??fixed-sidebar/1.1.7/fixed-sidebar.js" type="text/javascript"></script>
    <script src='//g.csdnimg.cn/common/csdn-report/report.js' type='text/javascript'></script>
    <link rel="stylesheet" type="text/css" href="https://csdnimg.cn/public/sandalstrap/1.4/css/sandalstrap.min.css">
    <style>
        .MathJax, .MathJax_Message, .MathJax_Preview{
            display: none
        }
    </style>
    <script src="https://dup.baidustatic.com/js/ds.js"></script>
</head>
  <body class="nodata " style="">
        <script>
            var toolbarSearchExt = '{"landingWord":["react面试题"],"queryWord":"","tag":["react.js","javascript","前端"],"title":"2023版最新最全React面试题"}';
        </script>
    <script src="https://g.csdnimg.cn/common/csdn-toolbar/csdn-toolbar.js" type="text/javascript"></script>
    <script>
    (function(){
        var bp = document.createElement('script');
        var curProtocol = window.location.protocol.split(':')[0];
        if (curProtocol === 'https') {
            bp.src = 'https://zz.bdstatic.com/linksubmit/push.js';
        }
        else {
            bp.src = 'http://push.zhanzhang.baidu.com/push.js';
        }
        var s = document.getElementsByTagName("script")[0];
        s.parentNode.insertBefore(bp, s);
    })();
    </script>
<link rel="stylesheet" href="https://csdnimg.cn/release/blogv2/dist/pc/css/blog_code-01256533b5.min.css">
<link rel="stylesheet" href="https://csdnimg.cn/release/blogv2/dist/mdeditor/css/editerView/chart-3456820cac.css" />
<link rel="stylesheet" href="https://g.csdnimg.cn/lib/swiper/6.0.4/css/swiper.css" />

<script src="https://g.csdnimg.cn/lib/swiper/6.0.4/js/swiper.js" async></script>

<script>
    var articleId = 129547714;
    var commentscount = 0;
    var curentUrl = "https://blog.csdn.net/LinkSLA/article/details/129547714";
    var myUrl = "https://my.csdn.net/";
    var highlight = ["javascript","react","2023","面试题","最全","前端","js","最新","版"];//高亮数组
    var isRecommendModule = true;
    var isBaiduPre = true;
    var baiduCount = 2;
    var setBaiduJsCount = 10;
    var share_card_url = "https://app-blog.csdn.net/share?article_id=129547714&username=LinkSLA"
	var articleType = 1;
    var baiduKey = "react面试题";
    var userNewReport = true;
    var needInsertBaidu = true;
    var recommendRegularDomainArr = ["blog.csdn.net/.+/article/details/","download.csdn.net/download/","edu.csdn.net/course/detail/","ask.csdn.net/questions/","bbs.csdn.net/topics/","www.csdn.net/gather_.+/"]
    var codeStyle = "";
    var baiduSearchType = "baidulandingword";
     var sharData = "{\"hot\":[{\"id\":1,\"url\":\"https:\\/\\/img-blog.csdnimg.cn\\/a5f4260710904e538002a6ab337939b3.png\"},{\"id\":2,\"url\":\"https:\\/\\/img-blog.csdnimg.cn\\/188b37199a2c4b74b1d9ffc39e0d52de.png\"},{\"id\":3,\"url\":\"https:\\/\\/img-blog.csdnimg.cn\\/14ded358b631444581edd98a256bc5af.png\"},{\"id\":4,\"url\":\"https:\\/\\/img-blog.csdnimg.cn\\/1470f23a770444d986ad551b9c33c5be.png\"},{\"id\":5,\"url\":\"https:\\/\\/img-blog.csdnimg.cn\\/c329f5181dc74f6c9bd28c982bb9f91d.png\"},{\"id\":6,\"url\":\"https:\\/\\/img-blog.csdnimg.cn\\/ccd8a3305e81460f9c505c95b432a65f.png\"},{\"id\":7,\"url\":\"https:\\/\\/img-blog.csdnimg.cn\\/bc89d8283389440d97fc4d30e30f45e1.png\"},{\"id\":8,\"url\":\"https:\\/\\/img-blog.csdnimg.cn\\/452d485b4a654f5592390550d2445edf.png\"},{\"id\":9,\"url\":\"https:\\/\\/img-blog.csdnimg.cn\\/f8b9939db2ed474a8f43a643015fc8b7.png\"},{\"id\":10,\"url\":\"https:\\/\\/img-blog.csdnimg.cn\\/6de8864187ab4ed3b1db0856369c36ff.png\"},{\"id\":11,\"url\":\"https:\\/\\/img-blog.csdnimg.cn\\/673cc3470ff74072acba958dc0c46e2d.png\"},{\"id\":12,\"url\":\"https:\\/\\/img-blog.csdnimg.cn\\/930c119760ac4491804db80f9c6d4e3f.png\"},{\"id\":13,\"url\":\"https:\\/\\/img-blog.csdnimg.cn\\/15e6befb05a24233bc2b65e96aa8d972.png\"},{\"id\":14,\"url\":\"https:\\/\\/img-blog.csdnimg.cn\\/2075fd6822184b95a41e214de4daec13.png\"},{\"id\":15,\"url\":\"https:\\/\\/img-blog.csdnimg.cn\\/859b1552db244eb6891a809263a5c657.png\"},{\"id\":16,\"url\":\"https:\\/\\/img-blog.csdnimg.cn\\/0be2f920f1f74290a98921974a9613fd.png\"},{\"id\":17,\"url\":\"https:\\/\\/img-blog.csdnimg.cn\\/2e97e00b43f14afab494ea55ef3f4a6e.png\"},{\"id\":18,\"url\":\"https:\\/\\/img-blog.csdnimg.cn\\/ff4ab252f46e444686f5135d6ebbfec0.png\"},{\"id\":19,\"url\":\"https:\\/\\/img-blog.csdnimg.cn\\/ae029bbe99564e79911657912d36524f.png\"},{\"id\":20,\"url\":\"https:\\/\\/img-blog.csdnimg.cn\\/b3ece39963de440388728e9e7b9bf427.png\"},{\"id\":21,\"url\":\"https:\\/\\/img-blog.csdnimg.cn\\/6f14651a99ba486e926d63b6fa692997.png\"},{\"id\":22,\"url\":\"https:\\/\\/img-blog.csdnimg.cn\\/83ceddf050084875a341e32dcceca721.png\"},{\"id\":23,\"url\":\"https:\\/\\/img-blog.csdnimg.cn\\/b90368b8fd5d4c6c8c79a707d877cf7c.png\"},{\"id\":24,\"url\":\"https:\\/\\/img-blog.csdnimg.cn\\/aeffae14ecf14e079b2616528c9a393b.png\"},{\"id\":25,\"url\":\"https:\\/\\/img-blog.csdnimg.cn\\/c5a06b5a13d44d16bed868fc3384897a.png\"},{\"id\":26,\"url\":\"https:\\/\\/img-blog.csdnimg.cn\\/08b697658b844b318cea3b119e9541ef.png\"},{\"id\":27,\"url\":\"https:\\/\\/img-blog.csdnimg.cn\\/68ccb0b8d09346ac961d2b5c1a8c77bf.png\"},{\"id\":28,\"url\":\"https:\\/\\/img-blog.csdnimg.cn\\/a2227a247e37418cbe0ea972ba6a859b.png\"},{\"id\":29,\"url\":\"https:\\/\\/img-blog.csdnimg.cn\\/3a42825fede748f9993e5bb844ad350d.png\"},{\"id\":30,\"url\":\"https:\\/\\/img-blog.csdnimg.cn\\/8882abc1dd484224b636966ea38555c3.png\"},{\"id\":31,\"url\":\"https:\\/\\/img-blog.csdnimg.cn\\/4f6a5f636a3e444d83cf8cc06d87a159.png\"},{\"id\":32,\"url\":\"https:\\/\\/img-blog.csdnimg.cn\\/1953ef79c56b4407b78d7181bdff11c3.png\"},{\"id\":33,\"url\":\"https:\\/\\/img-blog.csdnimg.cn\\/c04a2a4f772948ed85b5b0380ed36287.png\"},{\"id\":34,\"url\":\"https:\\/\\/img-blog.csdnimg.cn\\/5b4fecd05091405ea04d8c0f53e9f2c7.png\"},{\"id\":35,\"url\":\"https:\\/\\/img-blog.csdnimg.cn\\/b89f576d700344e280d6ceb2a66c2420.png\"},{\"id\":36,\"url\":\"https:\\/\\/img-blog.csdnimg.cn\\/1c65780e11804bbd9971ebadb3d78bcf.png\"},{\"id\":37,\"url\":\"https:\\/\\/img-blog.csdnimg.cn\\/d590db2055f345db9706eb68a7ec151a.png\"},{\"id\":38,\"url\":\"https:\\/\\/img-blog.csdnimg.cn\\/fe602f80700b4f6fb3c4a9e4c135510e.png\"},{\"id\":39,\"url\":\"https:\\/\\/img-blog.csdnimg.cn\\/39ff2fcd31e04feba301a071976a0ba7.png\"},{\"id\":40,\"url\":\"https:\\/\\/img-blog.csdnimg.cn\\/f9b61b3d113f436b828631837f89fb39.png\"},{\"id\":41,\"url\":\"https:\\/\\/img-blog.csdnimg.cn\\/df1aca5f610c4ad48cd16da88c9c8499.png\"},{\"id\":42,\"url\":\"https:\\/\\/img-blog.csdnimg.cn\\/d7acf73a1e6b41399a77a85040e10961.png\"},{\"id\":43,\"url\":\"https:\\/\\/img-blog.csdnimg.cn\\/b7f1b63542524b97962ff649ab4e7e23.png\"}],\"vip\":[{\"id\":1,\"vipUrl\":\"https:\\/\\/img-home.csdnimg.cn\\/images\\/20220920101150.png\",\"url\":\"https:\\/\\/img-home.csdnimg.cn\\/images\\/20220920101154.png\"},{\"id\":2,\"vipUrl\":\"https:\\/\\/img-home.csdnimg.cn\\/images\\/20220920101204.png\",\"url\":\"https:\\/\\/img-home.csdnimg.cn\\/images\\/20220920101208.png\"},{\"id\":3,\"vipUrl\":\"https:\\/\\/img-home.csdnimg.cn\\/images\\/20220920101211.png\",\"url\":\"https:\\/\\/img-home.csdnimg.cn\\/images\\/20220920101215.png\"},{\"id\":4,\"vipUrl\":\"https:\\/\\/img-home.csdnimg.cn\\/images\\/20220920101218.png\",\"url\":\"https:\\/\\/img-home.csdnimg.cn\\/images\\/20220920101220.png\"},{\"id\":5,\"vipUrl\":\"https:\\/\\/img-home.csdnimg.cn\\/images\\/20220920101223.png\",\"url\":\"https:\\/\\/img-home.csdnimg.cn\\/images\\/20220920101226.png\"},{\"id\":6,\"vipUrl\":\"https:\\/\\/img-home.csdnimg.cn\\/images\\/20220922100635.png\",\"url\":\"https:\\/\\/img-home.csdnimg.cn\\/images\\/20220922100639.png\"},{\"id\":7,\"vipUrl\":\"https:\\/\\/img-home.csdnimg.cn\\/images\\/20220922100642.png\",\"url\":\"https:\\/\\/img-home.csdnimg.cn\\/images\\/20220922100644.png\"},{\"id\":8,\"vipUrl\":\"https:\\/\\/img-home.csdnimg.cn\\/images\\/20220922100647.png\",\"url\":\"https:\\/\\/img-home.csdnimg.cn\\/images\\/20220922100649.png\"},{\"id\":9,\"vipUrl\":\"https:\\/\\/img-home.csdnimg.cn\\/images\\/20220922100652.png\",\"url\":\"https:\\/\\/img-home.csdnimg.cn\\/images\\/20220922100655.png\"},{\"id\":10,\"vipUrl\":\"https:\\/\\/img-blog.csdnimg.cn\\/55de67481fde4b04b97ad78f11fe369a.png\",\"url\":\"https:\\/\\/img-blog.csdnimg.cn\\/bb2418fb537e4d78b10d8765ccd810c5.png\"},{\"id\":11,\"vipUrl\":\"https:\\/\\/img-blog.csdnimg.cn\\/579c713394584d128104ef1044023954.png\",\"url\":\"https:\\/\\/img-blog.csdnimg.cn\\/f420d9fbcf5548079d31b5e809b6d6cd.png\"},{\"id\":12,\"vipUrl\":\"https:\\/\\/img-blog.csdnimg.cn\\/75b7f3155ba642f5a4cc16b7baf44122.png\",\"url\":\"https:\\/\\/img-blog.csdnimg.cn\\/a9030f5877be401f8b340b80b0d91e64.png\"},{\"id\":13,\"vipUrl\":\"https:\\/\\/img-blog.csdnimg.cn\\/0903d33cafa54934be3780aa54ae958d.png\",\"url\":\"https:\\/\\/img-blog.csdnimg.cn\\/2cd8c8929f5a42fca5da2a0aeb456203.png\"},{\"id\":14,\"vipUrl\":\"https:\\/\\/img-blog.csdnimg.cn\\/949fd7c22884439fbfc3c0e9c3b8dee7.png\",\"url\":\"https:\\/\\/img-blog.csdnimg.cn\\/dafbea9bd9eb4f3b962b48dc41657f89.png\"},{\"id\":15,\"vipUrl\":\"https:\\/\\/img-blog.csdnimg.cn\\/4119cfddd71d4e6a8a27a18dbb74d90e.png\",\"url\":\"https:\\/\\/img-blog.csdnimg.cn\\/c56310c8b6384d9e85388e4e342ce508.png\"},{\"id\":16,\"vipUrl\":\"https:\\/\\/img-blog.csdnimg.cn\\/121575274da142bcbbbbc2e8243dd411.png\",\"url\":\"https:\\/\\/img-blog.csdnimg.cn\\/5013993de06542f881018bb9abe2edf7.png\"},{\"id\":17,\"vipUrl\":\"https:\\/\\/img-blog.csdnimg.cn\\/4d97aa6dd4fe4f09a6bef5bdf8a6abcd.png\",\"url\":\"https:\\/\\/img-blog.csdnimg.cn\\/76f23877b6ad4066ad45ce8e31b4b977.png\"},{\"id\":18,\"vipUrl\":\"https:\\/\\/img-blog.csdnimg.cn\\/fdb619daf21b4c829de63b9ebc78859d.png\",\"url\":\"https:\\/\\/img-blog.csdnimg.cn\\/a1abe5d27a5441f599adfe662f510243.png\"},{\"id\":19,\"vipUrl\":\"https:\\/\\/img-blog.csdnimg.cn\\/676b7707bb11410f8f56bc0ed2b2345c.png\",\"url\":\"https:\\/\\/img-blog.csdnimg.cn\\/7ac5b467fbf24e1d8c2de3f3332c4f54.png\"},{\"id\":20,\"vipUrl\":\"https:\\/\\/img-blog.csdnimg.cn\\/0becb8cc227e4723b765bdd69a20fd4a.png\",\"url\":\"https:\\/\\/img-blog.csdnimg.cn\\/fdec85b26091486b9a89d0b8d45c3749.png\"},{\"id\":21,\"vipUrl\":\"https:\\/\\/img-blog.csdnimg.cn\\/1a6c06235ad44941b38c54cbc25a370c.png\",\"url\":\"https:\\/\\/img-blog.csdnimg.cn\\/410a06cda2d44b0c84578f88275caf70.png\"}],\"map\":{\"hot\":\"热门\",\"vip\":\"VIP\"}}";
    
    var canRead = true;
    var blogMoveHomeArticle = false;
    var showPcWindowAd = false;
    var showHeadWord = true;
    var showSearchText = "";
    var linkPage = true;
    var articleSource = 1;
    var articleReport = '{"spm":"1001.2101","extra":{"titAb":"t_1","tsab":"t_3","tag":"t_2"},"pid":"blog"}';
    var isShowToQuestion = false;
    var baiduSearchChannel = 'pc_relevant'
    var baiduSearchIdentification = '.235^v29^pc_relevant_default_base3'
    var distRequestId = '1681723272089_54543'
    var initRewardObject = {
        giver: "weixin_52215647",
        anchor: "LinkSLA",
        articleId: "129547714",
        sign: "1624336181fb0c9a24faf5f8b8e04c9e",
    }
    var isLikeStatus = false;
    var isUnLikeStatus = false;
    var studyLearnWord = "";
    var isCurrentUserVip = false;
    var testNewStyle = "oldStyle"
    var contentViewsHeight = 0;
    var contentViewsCount = 0;
    var contentViewsCountLimit = 5;
    var isShowConcision = true
    var isCookieConcision = false
    var isHasDirectoryModel = false
    var isShowSideModel = false
    var isShowDirectoryModel = true
    function getCookieConcision(sName){
        var allCookie = document.cookie.split("; ");
        for (var i=0; i < allCookie.length; i++){
            var aCrumb = allCookie[i].split("=");
            if (sName == aCrumb[0])
                return aCrumb[1];
        }
        return null;
    }
    if (getCookieConcision('blog_details_concision') && getCookieConcision('blog_details_concision') == 0){
        isCookieConcision = true
        isShowSideModel = true
        isShowDirectoryModel = false
    }
</script>
<div class="main_father clearfix d-flex justify-content-center mainfather-concision" style="height:100%;"> 
    <div class="container clearfix container-concision" id="mainBox">
        <script>
        if(!isCookieConcision){
            $('.main_father').removeClass('mainfather-concision')
            $('.main_father .container').removeClass('container-concision')
        }
        </script>
        <main>
<script type="text/javascript">
    function getQueryString(name) {   
      var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)"); //构造一个含有目标参数的正则表达式对象  
      var r = window.location.search.substr(1).match(reg);  //匹配目标参数
      if( r != null ) return decodeURIComponent( r[2] ); return '';   
    }
    function stripscript(s){ 
      var pattern = new RegExp("[`~!@#$^&*()=|{}':;',\\[\\].<>/?~！@#￥……&*（）——|{}【】‘；：”“'。，、？%]") 
      var rs = ""; 
      for (var i = 0; i < s.length; i++) { 
        rs = rs+s.substr(i, 1).replace(pattern, ''); 
      } 
      return rs;
    }
    var blogHotWords = stripscript(getQueryString('utm_term')).length > 1 ? stripscript(getQueryString('utm_term')) : ''
</script>
<div class="blog-content-box">
        <div class="article-header-box">
        <div class="article-header">
            <div class="article-title-box">
                <h1 class="title-article" id="articleContentId">2023版最新最全React面试题</h1>
            </div>
            <div class="article-info-box">
                <div class="article-bar-top">
                    <img class="article-type-img" src="https://csdnimg.cn/release/blogv2/dist/pc/img/original.png" alt="">
                    <div class="bar-content">
                    <a class="follow-nickName vip-name" href="https://blog.csdn.net/LinkSLA" target="_blank" rel="noopener" title="LinkSLA">LinkSLA</a>
                    <img class="article-time-img article-heard-img" src="https://csdnimg.cn/release/blogv2/dist/pc/img/newCurrentTime2.png" alt="">
                    <span class="time">于&nbsp;2023-03-15 10:40:03&nbsp;发布</span>
                    <img class="article-read-img article-heard-img" src="https://csdnimg.cn/release/blogv2/dist/pc/img/articleReadEyes2.png" alt="">
                    <span class="read-count">969</span>
                    <a id="blog_detail_zk_collection" class="un-collection" data-report-click='{"mod":"popu_823","spm":"1001.2101.3001.4232","ab":"new"}'>
                        <img class="article-collect-img article-heard-img un-collect-status isdefault" style="display:inline-block" src="https://csdnimg.cn/release/blogv2/dist/pc/img/tobarCollect2.png" alt="">
                        <img class="article-collect-img article-heard-img collect-status isactive" style="display:none" src="https://csdnimg.cn/release/blogv2/dist/pc/img/tobarCollectionActive2.png" alt="">
                        <span class="name">收藏</span>
                        <span class="get-collection">
                            12
                        </span>
                    </a>
                    </div>
                </div>
                
                <div class="operating">
                    <a class="href-article-edit slide-toggle">版权</a>
                </div>
            </div>
        </div>
    </div>
    <article class="baidu_pl">
        <div id="article_content" class="article_content clearfix">
        <link rel="stylesheet" href="https://csdnimg.cn/release/blogv2/dist/mdeditor/css/editerView/kdoc_html_views-1a98987dfd.css">
        <link rel="stylesheet" href="https://csdnimg.cn/release/blogv2/dist/mdeditor/css/editerView/ck_htmledit_views-25cebea3f9.css">
                <div id="content_views" class="htmledit_views">
                    <p>React 作为前端使用最多的框架&#xff0c;必然是面试的重点。我们接下来主要从 React 的使用方式、源码层面和周边生态&#xff08;如 redux, react-router 等&#xff09;等几个方便来进行总结。</p> 
<h2 id="1-使用方式上">1. 使用方式上</h2> 
<p>这里主要考察的是&#xff0c;在开发使用过程中&#xff0c;对 React 框架的了解&#xff0c;如 hook 的不同调用方式得到的结果、函数组件中的 useState 和类组件的 state 的区别等等。</p> 
<h3 id="props-的变动是否会引起-state-hook-中数据的变动">props 的变动&#xff0c;是否会引起 state hook 中数据的变动&#xff1f;</h3> 
<p>React 组件的 props 变动&#xff0c;会让组件重新执行&#xff0c;但并不会引起 state 的值的变动。state 值的变动&#xff0c;只能由 setState() 来触发。因此若想在 props 变动时&#xff0c;重置 state 的数据&#xff0c;需要监听 props 的变动&#xff0c;如&#xff1a;</p> 
<pre><code>const App &#61; props &#61;&gt; {
  const [count, setCount] &#61; useState(0);

  // 监听 props 的变化&#xff0c;重置 count 的值
  useEffect(() &#61;&gt; {
    setCount(0);
  }, [props]);

  return &lt;div onClick&#61;{() &#61;&gt; setCount(count &#43; 1)}&gt;{count}&lt;/div&gt;;
};
</code></pre> 
<h3 id="react18-有哪些新变化">React18 有哪些新变化&#xff1f;</h3> 
<p>React 的更新都是渐进式的更新&#xff0c;在 React18 中启用的新特性&#xff0c;其实在 v17 中&#xff08;甚至更早&#xff09;就埋下了。</p> 
<ol><li>并发渲染机制&#xff1a;根据用户的设备性能和网速对渲染过程进行适当的调整&#xff0c; 保证 React 应用在长时间的渲染过程中依旧保持可交互性&#xff0c;避免页面出现卡顿或无响应的情况&#xff0c;从而提升用户体验。</li><li>新的创建方式&#xff1a;现在是要先通过<code>createRoot()</code>创建一个 root 节点&#xff0c;然后该 root 节点来调用<code>render()</code>方法&#xff1b;</li><li>自动批处理优化&#xff1a;批处理&#xff1a; React 将多个状态更新分组到一个重新渲染中以获得更好的性能。&#xff08;将多次 setstate 事件合并&#xff09;&#xff1b;在 v18 之前只在事件处理函数中实现了批处理&#xff0c;在 v18 中所有更新都将自动批处理&#xff0c;包括 promise 链、setTimeout 等异步代码以及原生事件处理函数&#xff1b;</li><li>startTransition&#xff1a;主动降低优先级。比如「搜索引擎的关键词联想」&#xff0c;用户在输入框中的输入希望是实时的&#xff0c;而联想词汇可以稍稍延迟一会儿。我们可以用 startTransition 来降低联想词汇更新的优先级&#xff1b;</li><li>useId&#xff1a;主要用于 SSR 服务端渲染的场景&#xff0c;方便在服务端渲染和客户端渲染时&#xff0c;产生唯一的 id&#xff1b;</li></ol>
<h3 id="并发模式是如何执行的">并发模式是如何执行的&#xff1f;</h3> 
<p>React 中的<code>并发</code>&#xff0c;并不是指同一时刻同时在做多件事情。因为 js 本身就是单线程的&#xff08;同一时间只能执行一件事情&#xff09;&#xff0c;而且还要跟 UI 渲染竞争主线程。若一个很耗时的任务占据了线程&#xff0c;那么后续的执行内容都会被阻塞。为了避免这种情况&#xff0c;React 就利用 fiber 结构和时间切片的机制&#xff0c;将一个大任务分解成多个小任务&#xff0c;然后按照任务的优先级和线程的占用情况&#xff0c;对任务进行调度。</p> 
<ul><li>对于每个更新&#xff0c;为其分配一个优先级 lane&#xff0c;用于区分其紧急程度。</li><li>通过 Fiber 结构将不紧急的更新拆分成多段更新&#xff0c;并通过宏任务的方式将其合理分配到浏览器的帧当中。这样就能使得紧急任务能够插入进来。</li><li>高优先级的更新会打断低优先级的更新&#xff0c;等高优先级更新完成后&#xff0c;再开始低优先级更新。</li></ul>
<h3 id="什么是受控组件和非受控组件">什么是受控组件和非受控组件&#xff1f;</h3> 
<p>我们稍微了解下什么是受控组件和非受控组件&#xff1a;</p> 
<ul><li>受控组件&#xff1a;只能通过 React 修改数据或状态的组件&#xff0c;就是受控组件&#xff1b;</li><li>非受控组件&#xff1a;与受控组件相反&#xff0c;如 input, textarea, select, checkbox 等组件&#xff0c;本身控件自己就能控制数据和状态的变更&#xff0c;而且 React 是不知道这些变更的&#xff1b;</li></ul>
<p>那么如何将非受控组件改为受控组件呢&#xff1f;那就是把上面的这些纯 html 组件数据或状态的变更&#xff0c;交给 React 来操作&#xff1a;</p> 
<pre><code>const App &#61; () &#61;&gt; {
  const [value, setValue] &#61; useState(&#39;&#39;);
  const [checked, setChecked] &#61; useState(false);

  return (
    &lt;&gt;
      &lt;input value&#61;{value} onInput&#61;{event &#61;&gt; setValue(event.target.value)} /&gt;
      &lt;input type&#61;&#34;checkbox&#34; checked&#61;{checked} onChange&#61;{event &#61;&gt; setChecked(event.target.checked)} /&gt;
    &lt;/&gt;
  );
};
</code></pre> 
<p>上面代码中&#xff0c;输入框和 checkbox 的变化&#xff0c;均是经过了 React 来操作的&#xff0c;在数据变更时&#xff0c;React 是能够知道的。</p> 
<h3 id="高阶组件hoc">高阶组件&#xff08;HOC&#xff09;&#xff1f;</h3> 
<h3 id="高阶组件">高阶组件&#xff1f;</h3> 
<p>高阶组件通过包裹&#xff08;wrapped&#xff09;被传入的 React 组件&#xff0c;经过一系列处理&#xff0c;最终返回一个相对增强&#xff08;enhanced&#xff09;的 React 组件&#xff0c;供其他组件调用。</p> 
<p>作用&#xff1a;</p> 
<ol><li>复用逻辑&#xff1a;高阶组件更像是一个加工 react 组件的工厂&#xff0c;批量对原有组件进行加工&#xff0c;包装处理。我们可以根据业务需求定制化专属的 HOC,这样可以解决复用逻辑。</li><li>强化 props&#xff1a;这个是 HOC 最常用的用法之一&#xff0c;高阶组件返回的组件&#xff0c;可以劫持上一层传过来的 props,然后混入新的 props,来增强组件的功能。代表作 react-router 中的 withRouter。</li><li>赋能组件&#xff1a;HOC 有一项独特的特性&#xff0c;就是可以给被 HOC 包裹的业务组件&#xff0c;提供一些拓展功能&#xff0c;比如说额外的生命周期&#xff0c;额外的事件&#xff0c;但是这种 HOC&#xff0c;可能需要和业务组件紧密结合。典型案例 react-keepalive-router 中的 keepaliveLifeCycle 就是通过 HOC 方式&#xff0c;给业务组件增加了额外的生命周期。</li><li>控制渲染&#xff1a;劫持渲染是 hoc 一个特性&#xff0c;在 wrapComponent 包装组件中&#xff0c;可以对原来的组件&#xff0c;进行条件渲染&#xff0c;节流渲染&#xff0c;懒加载等功能&#xff0c;后面会详细讲解&#xff0c;典型代表做 react-redux 中 connect 和 dva 中 dynamic 组件懒加载。</li></ol>
<p>参考&#xff1a;<a href="https://juejin.cn/post/6940422320427106335" title="react 进阶」一文吃透 React 高阶组件(HOC)">react 进阶」一文吃透 React 高阶组件(HOC)</a></p> 
<h3 id="react-中为什么要使用-hook">React 中为什么要使用 Hook&#xff1f;</h3> 
<p>官方网站有介绍该原因&#xff1a;<a href="https://zh-hans.reactjs.org/docs/hooks-intro.html#motivation" title="使用 Hook 的动机">使用 Hook 的动机</a>。</p> 
<p>这里我们简要的提炼下&#xff1a;</p> 
<ol><li>在组件之间复用状态逻辑很难&#xff1a;在类组件中&#xff0c;可能需要 render props 和 高阶组件等方式&#xff0c;但会形成“嵌套地域”&#xff1b;而使用 Hook&#xff0c;则可以从组件中提取状态逻辑&#xff0c;是的这些逻辑可以单独测试并复用&#xff1b;</li><li>复杂组件变得难以理解&#xff1a;在类组件中&#xff0c;每个生命周期常常包含一些不相关的逻辑。如不同的执行逻辑&#xff0c;都要放在<code>componentDidMount</code>中执行和获取数据&#xff0c;而之后需在 <code>componentWillUnmount</code> 中清除&#xff1b;但在函数组件中&#xff0c;不同的逻辑可以放在不同的 Hook 中执行&#xff0c;互不干扰&#xff1b;</li><li>难以理解的 class&#xff1a;类组件中&#xff0c;充斥着各种对 <code>this</code> 的使用&#xff0c;如 <code>this.onClick.bind(this)</code>&#xff0c;<code>this.state</code>&#xff0c;<code>this.setState()</code> 等&#xff0c;同时&#xff0c;class 不能很好的压缩&#xff0c;并且会使热重载出现不稳定的情况&#xff1b;Hook 使你在非 class 的情况下可以使用更多的 React 特性&#xff1b;</li></ol>
<h3 id="usecallback-和-usememo-的使用场景">useCallback 和 useMemo 的使用场景</h3> 
<p>useCallback 和 useMemo 可以用来缓存函数和变量&#xff0c;提高性能&#xff0c;减少资源浪费。但并不是所有的函数和变量都需要用这两者来实现&#xff0c;他也有对应的使用场景。</p> 
<p>我们知道 useCallback 可以缓存函数体&#xff0c;在依赖项没有变化时&#xff0c;前后两次渲染时&#xff0c;使用的函数体是一样的。它的使用场景是&#xff1a;</p> 
<ul><li>函数作为其他 hook 的依赖项时&#xff08;如在 useEffect()中&#xff09;&#xff1b;</li><li>函数作为 React.memo()&#xff08;或 shouldComponentUpdate &#xff09;中的组件的 props&#xff1b;</li></ul>
<p>主要是为了避免重新生成的函数&#xff0c;会导致其他 hook 或组件的不必要刷新。</p> 
<p>useMemo 用来缓存函数执行的结果。如每次渲染时都要执行一段很复杂的运算&#xff0c;或者一个变量需要依赖另一个变量的运算结果&#xff0c;就都可以使用 useMemo()。</p> 
<p>参考文章&#xff1a;<a href="https://www.xiabingbao.com/post/react/react-usecallback-usememo-rjp9zn.html" title="React18 源码解析之 useCallback 和 useMemo">React18 源码解析之 useCallback 和 useMemo</a>。</p> 
<h3 id="usestate-的传参方式有什么区别">useState 的传参方式&#xff0c;有什么区别&#xff1f;</h3> 
<p>useState()的传参有两种方式&#xff1a;纯数据和回调函数。这两者在初始化时&#xff0c;除了传入方式不同&#xff0c;没啥区别。但在调用时&#xff0c;不同的调用方式和所在环境&#xff0c;输出的结果也是不一样的。</p> 
<p>如&#xff1a;</p> 
<pre><code>const App &#61; () &#61;&gt; {
  const [count, setCount] &#61; useState(0);

  const handleParamClick &#61; () &#61;&gt; {
    setCount(count &#43; 1);
    setCount(count &#43; 1);
    setCount(count &#43; 1);
  };

  const handleCbClick &#61; () &#61;&gt; {
    setCount(count &#61;&gt; count &#43; 1);
    setCount(count &#61;&gt; count &#43; 1);
    setCount(count &#61;&gt; count &#43; 1);
  };
};
</code></pre> 
<p>上面的两种传入方式&#xff0c;最后得到的 count 结果是不一样的。为什么呢&#xff1f;因为在以数据的格式传参时&#xff0c;这 3 个使用的是同一个 count 变量&#xff0c;数值是一样的。相当于<code>setCount(0 &#43; 1)</code>&#xff0c;调用了 3 次&#xff1b;但以回调函数的传参方式&#xff0c;React 则一般地会直接该回调函数&#xff0c;然后得到最新结果并存储到 React 内部&#xff0c;下次使用时就是最新的了。注意&#xff1a;这个最新值是保存在 React 内部的&#xff0c;外部的 count 并不会马上更新&#xff0c;只有在下次渲染后才会更新。</p> 
<p>还有&#xff0c;在定时器中&#xff0c;两者得到的结果也是不一样的&#xff1a;</p> 
<pre><code>const App &#61; () &#61;&gt; {
  const [count, setCount] &#61; useState(0);

  useEffect(() &#61;&gt; {
    const timer &#61; setInterval(() &#61;&gt; {
      setCount(count &#43; 1);
    }, 500);
    return () &#61;&gt; clearInterval(timer);
  }, []);

  useEffect(() &#61;&gt; {
    const timer &#61; setInterval(() &#61;&gt; {
      setCount(count &#61;&gt; count &#43; 1);
    }, 500);
    return () &#61;&gt; clearInterval(timer);
  }, []);
};
</code></pre> 
<h3 id="为什么在本地开发时组件会渲染两次">为什么在本地开发时&#xff0c;组件会渲染两次&#xff1f;</h3> 
<p><a href="https://github.com/wenzi0github/react/issues/2" title="issues#2">issues#2</a></p> 
<p>在 React.StrictMode 模式下&#xff0c;如果用了 useState,usesMemo,useReducer 之类的 Hook&#xff0c;React 会故意渲染两次&#xff0c;为的就是将一些不容易发现的错误容易暴露出来&#xff0c;同时 React.StrictMode 在正式环境中不会重复渲染。</p> 
<p>也就是在测试环境的严格模式下&#xff0c;才会渲染两次。</p> 
<h3 id="如何实现组件的懒加载">如何实现组件的懒加载</h3> 
<p>从 16.6.0 开始&#xff0c;React 提供了 lazy 和 Suspense 来实现懒加载。</p> 
<pre><code>import React, { lazy, Suspense } from &#39;react&#39;;
const OtherComponent &#61; lazy(() &#61;&gt; import(&#39;./OtherComponent&#39;));

function MyComponent() {
  return (
    &lt;Suspense fallback&#61;{&lt;div&gt;Loading...&lt;/div&gt;}&gt;
      &lt;OtherComponent /&gt;
    &lt;/Suspense&gt;
  );
}
</code></pre> 
<p>属性<code>fallback</code>表示在加载组件前&#xff0c;渲染的内容。</p> 
<h3 id="如何实现一个定时器的-hook">如何实现一个定时器的 hook</h3> 
<p>若在定时器内直接使用 React 的代码&#xff0c;可能会收到意想不到的结果。如我们想实现一个每 1 秒加 1 的定时器&#xff1a;</p> 
<pre><code>const App &#61; () &#61;&gt; {
  const [count, setCount] &#61; useState(0);

  useEffect(() &#61;&gt; {
    const timer &#61; setInterval(() &#61;&gt; {
      setCount(count &#43; 1);
    }, 1000);
    return () &#61;&gt; clearInterval(timer);
  }, []);

  return &lt;div className&#61;&#34;App&#34;&gt;{count}&lt;/div&gt;;
};
</code></pre> 
<p>可以看到&#xff0c;coun 从 0 变成 1 以后&#xff0c;就再也不变了。为什么会这样&#xff1f;</p> 
<p class="img-center"><img alt="" src="https://img-blog.csdnimg.cn/img_convert/5a2dd7772499063db0b3919c13fadc91.webp?x-oss-process&#61;image/format,png" /></p> 
<p>尽管由于定时器的存在&#xff0c;组件始终会一直重新渲染&#xff0c;但定时器的回调函数是挂载期间定义的&#xff0c;所以它的闭包永远是对挂载时 Counter 作用域的引用&#xff0c;故 count 永远不会超过 1。</p> 
<p>针对这个单一的 hook 调用&#xff0c;还比较好解决&#xff0c;例如可以监听 count 的变化&#xff0c;或者通过 useState 的 callback 传参方式。</p> 
<pre><code>const App &#61; () &#61;&gt; {
  const [count, setCount] &#61; useState(0);

  // 监听 count 的变化&#xff0c;不过这里将定时器改成了 setTimeout
  // 即使不修改&#xff0c;setInterval()的timer也会在每次渲染时被清除掉&#xff0c;
  // 然后重新启动一个新的定时器
  useEffect(() &#61;&gt; {
    const timer &#61; setTimeout(() &#61;&gt; {
      setCount(count &#43; 1);
    }, 1000);
    return () &#61;&gt; clearInterval(timer);
  }, [count]);

  // 以回调的方式
  // 回调的方式&#xff0c;会计算回调的结果&#xff0c;然后作为下次更新的初始值
  // 详情可见&#xff1a; https://www.xiabingbao.com/post/react/react-usestate-rn5bc0.html#5.&#43;updateReducer
  useEffect(() &#61;&gt; {
    const timer &#61; setInterval(() &#61;&gt; {
      setCount(count &#61;&gt; count &#43; 1);
    }, 1000);
    return () &#61;&gt; clearInterval(timer);
  }, []);

  return &lt;div className&#61;&#34;App&#34;&gt;{count}&lt;/div&gt;;
};
</code></pre> 
<p>当然还有别的方式也可以实现 count 的更新。那要是调用更多的 hook&#xff0c;或者更复杂的代码&#xff0c;该怎么办呢&#xff1f;这里我们可以封装一个新的 hook 来使用&#xff1a;</p> 
<pre><code>// https://overreacted.io/zh-hans/making-setinterval-declarative-with-react-hooks/
const useInterval &#61; (callback: () &#61;&gt; void, delay: number | null): void &#61;&gt; {
  const savedCallback &#61; useRef(callback);

  useEffect(() &#61;&gt; {
    savedCallback.current &#61; callback;
  });

  useEffect(() &#61;&gt; {
    function tick() {
      savedCallback.current();
    }
    if (delay !&#61;&#61; null) {
      const id &#61; setInterval(tick, delay);
      return () &#61;&gt; clearInterval(id);
    }
  }, [delay]);
};
</code></pre> 
<h3 id="useeffect的清除机制是什么在什么时候执行">useEffect()的清除机制是什么&#xff1f;在什么时候执行&#xff1f;</h3> 
<p>useEffect(callback)的回调函数里&#xff0c;若有返回的函数&#xff0c;这是 effect 可选的清除机制。每个 effect 都可以返回一个清除函数。</p> 
<p>React 何时清除 effect&#xff1f; React 会在组件卸载的时候执行清除操作。同时&#xff0c;若组件产生了更新&#xff0c;会先执行上一个的清除函数&#xff0c;然后再运行下一个 effect。如</p> 
<pre><code>// 运行第一个 effect

// 产生更新时
// 清除上一个 effect
// 运行下一个 effect

// 产生更新时
// 清除上一个 effect
// 运行下一个 effect

// 组件卸载时
// 清除最后一个 effect
</code></pre> 
<p>参考&#xff1a;<a href="https://zh-hans.reactjs.org/docs/hooks-effect.html#explanation-why-effects-run-on-each-update" title="为什么每次更新的时候都要运行 Effect">为什么每次更新的时候都要运行 Effect</a></p> 
<h2 id="2-源码层面上">2. 源码层面上</h2> 
<p>这部分考察的就更有深度一些了&#xff0c;多多少少得了解一些源码&#xff0c;才能明白其中的缘由&#xff0c;比如 React 的 diff 对比&#xff0c;循环中 key 的作用等。</p> 
<h3 id="虚拟-dom-有什么优点真实-dom-和虚拟-dom谁快">虚拟 dom 有什么优点&#xff1f;真实 dom 和虚拟 dom&#xff0c;谁快&#xff1f;</h3> 
<p>Virtual DOM 是以对象的方式来描述真实 dom 对象的&#xff0c;那么在做一些 update 的时候&#xff0c;可以在内存中进行数据比对&#xff0c;减少对真实 dom 的操作减少浏览器重排重绘的次数&#xff0c;减少浏览器的压力&#xff0c;提高程序的性能&#xff0c;并且因为 diff 算法的差异比较&#xff0c;记录了差异部分&#xff0c;那么在开发中就会帮助程序员减少对差异部分心智负担&#xff0c;提高了开发效率。</p> 
<p>虚拟 dom 好多这么多&#xff0c;渲染速度上是不是比直接操作真实 dom 快呢&#xff1f;并不是。虚拟 dom 增加了一层内存运算&#xff0c;然后才操作真实 dom&#xff0c;将数据渲染到页面上。渲染上肯定会慢上一些。虽然虚拟 dom 的缺点在初始化时增加了内存运算&#xff0c;增加了首页的渲染时间&#xff0c;但是运算时间是以毫秒级别或微秒级别算出的&#xff0c;对用户体验影响并不是很大。</p> 
<h3 id="什么是合成事件与原生事件有什么区别">什么是合成事件&#xff0c;与原生事件有什么区别&#xff1f;</h3> 
<p>React 中所有触发的事件&#xff0c;都是自己在其内部封装了一套事件机制。目的是为了实现全浏览器的一致性&#xff0c;抹平不同浏览器之间的差异性。</p> 
<p>在 React17 之前&#xff0c;React 是把事件委托在 document 上的&#xff0c;React17 及以后版本不再把事件委托在 document 上&#xff0c;而是委托在挂载的容器上。React 合成事件采用的是事件冒泡机制&#xff0c;当在某具体元素上触发事件时&#xff0c;等冒泡到顶部被挂载事件的那个元素时&#xff0c;才会真正地执行事件。</p> 
<p>而原生事件&#xff0c;当某具体元素触发事件时&#xff0c;会立刻执行该事件。因此若要比较事件触发的先后时机时&#xff0c;原生事件会先执行&#xff0c;React 合成事件会后执行。</p> 
<h3 id="key-的作用是什么">key 的作用是什么&#xff1f;</h3> 
<p>key 帮助 React 识别哪些元素改变了&#xff0c;比如被添加或删除。因此你应当给数组中的每一个元素赋予一个确定的标识。</p> 
<p>当组件刷新时&#xff0c;React 内部会根据 key 和元素的 type&#xff0c;来对比元素是否发生了变化。若选做 key 的数据有问题&#xff0c;可能会在更新的过程中产生异常。</p> 
<p>参考&#xff1a;<a href="https://www.xiabingbao.com/post/react/array-key-rifnwk.html" title="React18 源码解析之 key 的作用">React18 源码解析之 key 的作用</a>。</p> 
<h3 id="多次执行-usestate会触发多次更新吗">多次执行 useState()&#xff0c;会触发多次更新吗&#xff1f;</h3> 
<p>在 React18 中&#xff0c;无论是多个 useState()的 hook&#xff0c;还是操作&#xff08;dispatch&#xff09;多次的数据。只要他们在同一优先级&#xff0c;React 就会将他们合并到一起操作&#xff0c;最后再更新数据。</p> 
<p>这是基于 React18 的批处理机制。React 将多个状态更新分组到一个重新渲染中以获得更好的性能。&#xff08;将多次 setstate 事件合并&#xff09;&#xff1b;在 v18 之前只在事件处理函数中实现了批处理&#xff0c;在 v18 中所有更新都将自动批处理&#xff0c;包括 promise 链、setTimeout 等异步代码以及原生事件处理函数&#xff1b;</p> 
<p>参考&#xff1a;<a href="https://www.xiabingbao.com/post/react/react-usestate-rn5bc0.html#6.1&#43;%E5%A4%9A%E6%AC%A1%E8%B0%83%E7%94%A8&#43;useState%28%29&#43;%E4%B8%AD%E7%9A%84&#43;dispatch&#43;%E6%96%B9%E6%B3%95%EF%BC%8C%E4%BC%9A%E4%BA%A7%E7%94%9F%E5%A4%9A%E6%AC%A1%E6%B8%B2%E6%9F%93%E5%90%97%EF%BC%9F" title="多次调用 useState() 中的 dispatch 方法&#xff0c;会产生多次渲染吗&#xff1f;">多次调用 useState() 中的 dispatch 方法&#xff0c;会产生多次渲染吗&#xff1f;</a></p> 
<h3 id="usestate的-state-是否可以直接修改是否可以引起组件渲染">useState()的 state 是否可以直接修改&#xff1f;是否可以引起组件渲染&#xff1f;</h3> 
<p>首先声明&#xff0c;我们不应当直接修改 state 的值&#xff0c;一方面是无法刷新组件&#xff08;无法将新数据渲染到页面中&#xff09;&#xff0c;再有可能会对下次的更新产生影响。</p> 
<p>唯一有影响的&#xff0c;就是后续要使用该变量的地方&#xff0c;会使用到新数据。但若其他 useState() 导致了组件的刷新&#xff0c;刚才变量的值&#xff0c;若是基本类型&#xff08;比如数字、字符串等&#xff09;&#xff0c;会重置为修改之前的值&#xff1b;若是复杂类型&#xff0c;基于 js 的 对象引用 特性&#xff0c;也会同步修改 React 内部存储的数据&#xff0c;但不会引起视图的变化。</p> 
<p>参考&#xff1a;<a href="https://www.xiabingbao.com/post/react/react-usestate-rn5bc0.html#6.3&#43;%E7%9B%B4%E6%8E%A5%E4%BF%AE%E6%94%B9&#43;state&#43;%E7%9A%84%E5%80%BC%EF%BC%8C%E4%BC%9A%E6%80%8E%E6%A0%B7%EF%BC%9F" title="直接修改 state 的值&#xff0c;会怎样&#xff1f;">直接修改 state 的值&#xff0c;会怎样&#xff1f;</a></p> 
<h3 id="react-的-diff-过程">React 的 diff 过程</h3> 
<ol><li>React 只对比当前层级的节点&#xff0c;不跨层级进行比较&#xff1b;</li><li>根据不同的节点类型&#xff0c;如函数组件节点、类组件节点、普通 fiber 节点、数组节点等&#xff0c;进入不同的处理函数&#xff1b;</li><li>前后两个 fiber 节点进行对比&#xff0c;若 type 不一样&#xff0c;直接舍弃掉旧的 fiber 节点&#xff0c;创建新的 fiber 节点&#xff1b;若 key 不一样&#xff0c;则需要根据情况判断&#xff0c;若是单个元素&#xff0c;则直接舍弃掉&#xff0c;创建新的 fiber 节点&#xff1b;若是数字型的元素&#xff0c;则查找是否移动了位置&#xff0c;若没找到&#xff0c;则创建新的节点&#xff1b;若 key 和 type 都一样&#xff0c;则接着往下递归&#xff1b;</li><li>若是单个 fiber 节点&#xff0c;则直接返回&#xff1b;若是并列多个元素的 fiber 节点&#xff0c;这里会形成单向链表&#xff0c;然后返回头指针&#xff08;该链表最前面的那个 fiber 节点&#xff09;&#xff1b;</li></ol>
<p>通过上面的 diff 对比过程&#xff0c;我们也可以看到&#xff0c;当组件产生比较大的变更时&#xff0c;React 需要做更多的动作&#xff0c;来构建出新的 fiber 树&#xff0c;因此我们在开发过程中&#xff0c;若从性能优化的角度考虑&#xff0c;尤其要注意的是&#xff1a;</p> 
<ol><li>节点不要产生大量的越级操作&#xff1a;因为 React 是只进行同层节点的对比&#xff0c;若同一个位置的子节点产生了比较大的变动&#xff0c;则只会舍弃掉之前的 fiber 节点&#xff0c;从而执行创建新 fiber 节点的操作&#xff1b;React 并不会把之前的 fiber 节点移动到另一个位置&#xff1b;相应的&#xff0c;之前的 jsx 节点移动到另一个位置后&#xff0c;在进行前后对比后&#xff0c;同样会执行更多的创建操作&#xff1b;</li><li>不修改节点的 key 和 type 类型&#xff0c;如使用随机数做为列表的 key&#xff0c;或从 div 标签改成 p 标签等操作&#xff0c;在 diff 对比过程中&#xff0c;都会直接舍弃掉之前的 fiber 节点及所有的子节点&#xff08;即使子节点没有变动&#xff09;&#xff0c;然后重新创建出新的 fiber 节点&#xff1b;</li></ol>
<p>参考&#xff1a;<a href="https://www.xiabingbao.com/post/react/reconcile-children-fiber-riezuz.html" title="React18 源码解析之 reconcileChildren 生成 fiber 的过程">React18 源码解析之 reconcileChildren 生成 fiber 的过程</a></p> 
<h3 id="基于-react-框架的特点可以有哪些优化措施">基于 React 框架的特点&#xff0c;可以有哪些优化措施&#xff1f;</h3> 
<ol><li>使用 React.lazy 和 Suspense 将页面设置为懒加载&#xff0c;避免 js 文件过大&#xff1b;</li><li>使用 SSR 同构直出技术&#xff0c;提高首屏的渲染速度&#xff1b;</li><li>使用 useCallback 和 useMemo 缓存函数或变量&#xff1b;使用 React.memo 缓存组件&#xff1b;</li><li>尽量调整样式或 className 的变动&#xff0c;减少 jsx 元素上的变动&#xff0c;尽量使用与元素相关的字段作为 key&#xff0c;可以减少 diff 的时间&#xff08;React 会尽量复用之前的节点&#xff0c;若 jsx 元素发生变动&#xff0c;就需要重新创建节点&#xff09;&#xff1b;</li><li>对于不需要产生页面变动的数据&#xff0c;可以放到 useRef()中&#xff1b;</li></ol>
<h3 id="reactchildrenmap-和-js-的-map-有什么区别">React.Children.map 和 js 的 map 有什么区别&#xff1f;</h3> 
<p>JavaScript 中的 map 不会对为 null 或者 undefined 的数据进行处理&#xff0c;而 React.Children.map 中的 map 可以处理 React.Children 为 null 或者 undefined 的情况。</p> 
<h2 id="3-周边生态">3. 周边生态</h2> 
<p>这部分主要考察 React 周边生态配套的了解&#xff0c;如状态管理库 redux、mobx&#xff0c;路由组件 react-router-dom 等。</p> 
<h3 id="react-router-和-react-router-dom-的有什么区别">react-router 和 react-router-dom 的有什么区别&#xff1f;</h3> 
<p>api 方面</p> 
<p>React-router&#xff1a; 提供了路由的核心 api。如 Router、Route、Switch 等&#xff0c;但没有提供有关 dom 操作进行路由跳转的 api&#xff1b;<br /> React-router-dom&#xff1a; 提供了 BrowserRouter、Route、Link 等 api&#xff0c;可以通过 dom 操作触发事件控制路由。<br /> Link 组件&#xff0c;会渲染一个 a 标签&#xff1b;BrowserRouter 和 HashRouter 组件&#xff0c;前者使用 pushState 和 popState 事件构建路由&#xff0c;后者使用 hash 和 hashchange 事件构建路由。</p> 
<p>使用区别</p> 
<p>react-router-dom 在 react-router 的基础上扩展了可操作 dom 的 api。 Swtich 和 Route 都是从 react-router 中导入了相应的组件并重新导出&#xff0c;没做什么特殊处理。<br /> react-router-dom 中 package.json 依赖中存在对 react-router 的依赖&#xff0c;故此&#xff0c;不需要额外安装 react-router。</p> 
<h3 id="redux-遵循的三个原则是什么">Redux 遵循的三个原则是什么&#xff1f;</h3> 
<ol><li>单一事实来源&#xff1a;整个应用的状态存储在单个 store 中的对象/状态树里。单一状态树可以更容易地跟踪随时间的变化&#xff0c;并调试或检查应用程序。</li><li>状态是只读的&#xff1a;改变状态的唯一方法是去触发一个动作。动作是描述变化的普通 JS 对象。就像 state 是数据的最小表示一样&#xff0c;该操作是对数据更改的最小表示。</li><li>使用纯函数进行更改&#xff1a;为了指定状态树如何通过操作进行转换&#xff0c;你需要纯函数。纯函数是那些返回值仅取决于其参数值的函数。</li></ol>
<h3 id="你对单一事实来源有什么理解">你对“单一事实来源”有什么理解&#xff1f;</h3> 
<p>Redux 使用 “Store” 将程序的整个状态存储在同一个地方。因此所有组件的状态都存储在 Store 中&#xff0c;并且它们从 Store 本身接收更新。单一状态树可以更容易地跟踪随时间的变化&#xff0c;并调试或检查程序。</p> 
<h3 id="redux-有哪些优点">Redux 有哪些优点&#xff1f;</h3> 
<p>Redux 的优点如下&#xff1a;</p> 
<ul><li>结果的可预测性 - 由于总是存在一个真实来源&#xff0c;即 store &#xff0c;因此不存在如何将当前状态与动作和应用的其他部分同步的问题。</li><li>可维护性 - 代码变得更容易维护&#xff0c;具有可预测的结果和严格的结构。</li><li>服务器端渲染 - 你只需将服务器上创建的 store 传到客户端即可。这对初始渲染非常有用&#xff0c;并且可以优化应用性能&#xff0c;从而提供更好的用户体验。</li><li>开发人员工具 - 从操作到状态更改&#xff0c;开发人员可以实时跟踪应用中发生的所有事情。</li><li>社区和生态系统 - Redux 背后有一个巨大的社区&#xff0c;这使得它更加迷人。一个由才华横溢的人组成的大型社区为库的改进做出了贡献&#xff0c;并开发了各种应用。</li><li>易于测试 - Redux 的代码主要是小巧、纯粹和独立的功能。这使代码可测试且独立。</li><li>组织 - Redux 准确地说明了代码的组织方式&#xff0c;这使得代码在团队使用时更加一致和简单。</li></ul>
<h2 id="4-总结">4. 总结</h2> 
<p>React 涉及到的相关知识点非常多&#xff0c;我也会经常更新的。</p> 
<p> </p>
                </div>
        </div>
        <div id="treeSkill"></div>
        <div id="blogExtensionBox" style="width:400px;margin:auto;margin-top:12px" class="blog-extension-box"></div>
    </article>
  <script>
  $(function() {
    setTimeout(function () {
      var mathcodeList = document.querySelectorAll('.htmledit_views img.mathcode');
      if (mathcodeList.length > 0) {
        var testImg = new Image();
        testImg.onerror = function () {
          mathcodeList.forEach(function (item) {
            $(item).before('<span class="img-codecogs">\\(' + item.alt + '\\)</span>');
            $(item).remove();
          })
          MathJax.Hub.Queue(["Typeset",MathJax.Hub]);
        }
        testImg.src = mathcodeList[0].src;
      }
    }, 1000)
  })
  </script>
</div>
<script type=text/javascript crossorigin src="https://csdnimg.cn/release/phoenix/production/qrcode-7c90a92189.min.js"></script>
<script src="//g.csdnimg.cn/??sharewx/1.2.1/sharewx.js" type="text/javascript"></script>
<script type="text/javascript" crossorigin src="https://g.csdnimg.cn/common/csdn-login-box/csdn-login-box.js"></script>
<script type="text/javascript" crossorigin src="https://g.csdnimg.cn/collection-box/2.1.1/collection-box.js"></script>                <div class="first-recommend-box recommend-box ">
<div class="recommend-item-box type_download clearfix" data-url="https://download.csdn.net/download/u010918911/63845521"  data-report-view='{"ab":"new","spm":"1001.2101.3001.6661.1","mod":"popu_871","extra":"{\"highlightScore\":0.0,\"utm_medium\":\"distribute.pc_relevant_t0.none-task-download-2~default~OPENSEARCH~Paid-1-63845521-blog-129547714.235^v29^pc_relevant_default_base3\",\"dist_request_id\":\"1681723272089_54543\"}","dist_request_id":"1681723272089_54543","ab_strategy":"increase_t0_download","index":"1","strategy":"2~default~OPENSEARCH~Paid","dest":"https://download.csdn.net/download/u010918911/63845521"}'>
</div>
                </div>
            <script src="https://csdnimg.cn/release/blogv2/dist/components/js/pc_wap_commontools-ad67eb7a7a.min.js" type="text/javascript" async></script>

<script src="https://g.csdnimg.cn/common/csdn-footer/csdn-footer.js" data-isfootertrack="false" type="text/javascript"></script>
<script type="text/javascript">
    window.csdn.csdnFooter.options = {
        el: '.blog-footer-bottom',
        type: 2
    }
</script>        </main>
<aside class="blog_container_aside">
    <!-- 详情页显示目录 -->
<!--文章目录-->
<div id="asidedirectory" class="aside-box">
    <div class='groupfile' id="directory">
        <h3 class="aside-title">目录</h3>
        <div class="align-items-stretch group_item">
            <div class="pos-box">
            <div class="scroll-box">
                <div class="toc-box">
                    <ol>
                        <li class="">
                            <a href="#1. 使用方式上">1. 使用方式上</a>
                        </li>
                    <li class="sub-box">
                    <ol>
                        <li class=""><a href="#props 的变动，是否会引起 state hook 中数据的变动？">props 的变动，是否会引起 state hook 中数据的变动？</a></li>
                        <li class=""><a href="#React18 有哪些新变化？">React18 有哪些新变化？</a></li>
                        <li class=""><a href="#并发模式是如何执行的？">并发模式是如何执行的？</a></li>
                        <li class="active">
                            <a href="#什么是受控组件和非受控组件？">什么是受控组件和非受控组件？</a>
                        </li>
                        <li>
                            <a href="#高阶组件（HOC）？">高阶组件（HOC）？</a>
                        </li>
                        <li>
                            <a href="#高阶组件？">高阶组件？</a>
                        </li>
                        <li><a href="#React 中为什么要使用 Hook？">React 中为什么要使用 Hook？</a></li>
                        <li><a href="#useCallback 和 useMemo 的使用场景">useCallback 和 useMemo 的使用场景</a></li>
                        <li><a href="#useState 的传参方式，有什么区别？">useState 的传参方式，有什么区别？</a></li>
                        <li><a href="#为什么在本地开发时，组件会渲染两次？">为什么在本地开发时，组件会渲染两次？</a></li>
                        <li><a href="#如何实现组件的懒加载">如何实现组件的懒加载</a></li>
                        <li><a href="#如何实现一个定时器的 hook">如何实现一个定时器的 hook</a></li>
                        <li><a href="#useEffect()的清除机制是什么？在什么时候执行？">useEffect()的清除机制是什么？在什么时候执行？</a></li></ol></li>
                        <li><a href="#2. 源码层面上">2. 源码层面上</a></li><li class="sub-box">
                    <ol>
                        
                        <li><a href="#虚拟 dom 有什么优点？真实 dom 和虚拟 dom，谁快？">虚拟 dom 有什么优点？真实 dom 和虚拟 dom，谁快？</a></li>
                        <li><a href="#什么是合成事件，与原生事件有什么区别？">什么是合成事件，与原生事件有什么区别？</a></li>
                        <li><a href="#key 的作用是什么？">key 的作用是什么？</a></li>
                        <li><a href="#多次执行 useState()，会触发多次更新吗？">多次执行 useState()，会触发多次更新吗？</a></li>
                        <li><a href="#useState()的 state 是否可以直接修改？是否可以引起组件渲染？">useState()的 state 是否可以直接修改？是否可以引起组件渲染？</a></li>
                        <li><a href="#React 的 diff 过程">React 的 diff 过程</a></li>
                        <li><a href="#基于 React 框架的特点，可以有哪些优化措施？">基于 React 框架的特点，可以有哪些优化措施？</a></li>
                        <li><a href="#React.Children.map 和 js 的 map 有什么区别？">React.Children.map 和 js 的 map 有什么区别？</a></li></ol></li>
                        <li><a href="#3. 周边生态">3. 周边生态</a></li><li class="sub-box">
                    <ol>
                        
                        <li><a href="#react-router 和 react-router-dom 的有什么区别？">react-router 和 react-router-dom 的有什么区别？</a></li>
                        <li><a href="#Redux 遵循的三个原则是什么？">Redux 遵循的三个原则是什么？</a></li>
                        <li><a href="#你对“单一事实来源”有什么理解？">你对“单一事实来源”有什么理解？</a></li>
                        <li><a href="#Redux 有哪些优点？">Redux 有哪些优点？</a></li></ol></li>
            </div>
            </div>
        </div>
    </div>
</div>
</aside>
<script>
	$("a.flexible-btn").click(function(){
		$(this).parents('div.aside-box').removeClass('flexible-box');
		$(this).parents("p.text-center").remove();
	})
</script>
<script type="text/javascript"  src="https://g.csdnimg.cn/user-tooltip/2.7/user-tooltip.js"></script>
<script type="text/javascript"  src="https://g.csdnimg.cn/user-medal/2.0.0/user-medal.js"></script>    </div>
<div class="recommend-right align-items-stretch clearfix" id="rightAside" data-type="recommend">
    <aside class="recommend-right_aside">
        <div id="recommend-right" >
                        <div class='flex-column aside-box groupfile' id="groupfile">
                <div class="groupfile-div">
                <h3 class="aside-title">目录</h3>
                <div class="align-items-stretch group_item">
                    <div class="pos-box">
                        <div class="scroll-box">
                            <div class="toc-box"></div>
                        </div>
                    </div>
                </div>
                </div>
            </div>
        </div>
    </aside>
</div>

<div class="recommend-right1  align-items-stretch clearfix" id="rightAsideConcision" data-type="recommend">
    <aside class="recommend-right_aside">
        <div id="recommend-right-concision" >
            <div class='flex-column aside-box groupfile' id="groupfileConcision">
                <div class="groupfile-div1">
                <h3 class="aside-title">目录</h3>
                <div class="align-items-stretch group_item">
                    <div class="pos-box">
                        <div class="scroll-box">
                            <div class="toc-box"></div>
                        </div>
                    </div>
                </div>
                </div>
            </div>
        </div>
    </aside>
</div>

</div>
<div class="mask-dark"></div>
<script src="https://csdnimg.cn/public/sandalstrap/1.4/js/sandalstrap.min.js"></script>


</div>

<div class="redEnvolope" id="redEnvolope">
  <div class="env-box">
    <div class="env-container">
      <div class="pre-open" id="preOpen">
        <div class="top">
          <header>
            <img class="clearTpaErr" :src="redpacketAuthor.avatar" alt="" />
            <div class="author">成就一亿技术人!</div>
          </header>
          <div class="bot-icon"></div>
        </div>
        <footer>
          <div class="red-openbtn open-start"></div>
          <div class="tip">
            领取后你会自动成为博主和红包主的粉丝
            <a class="rule" target="_blank">规则</a>
          </div>
        </footer>
      </div>
      <div class="opened" id="opened">
        <div class="bot-icon">
          <header>
            <a class="creatorUrl" href="" target="_blank">
              <img class="clearTpaErr" src="https://profile.csdnimg.cn/4/E/8/1_hope_wisdom" alt="" />
            </a>
            <div class="author">
              <div class="tt">hope_wisdom</div> 发出的红包
            </div>
          </header>
        </div>
        <div class="receive-box">
          <header></header>
          <div class="receive-list">
          </div>
        </div>
      </div>
    </div>
    <div class="close-btn"></div>
  </div>
</div>
</body>
    <!-- 富文本柱状图  -->
	<link rel="stylesheet" href="https://csdnimg.cn/release/blog_editor_html/release1.6.12/ckeditor/plugins/chart/chart.css"/>
	<script type="text/javascript" src="https://csdnimg.cn/release/blog_editor_html/release1.6.12/ckeditor/plugins/chart/lib/chart.min.js"></script>
    <script type="text/javascript" src="https://csdnimg.cn/release/blog_editor_html/release1.6.12/ckeditor/plugins/chart/widget2chart.js"></script>
<script src="https://csdnimg.cn/release/blogv2/dist/components/js/axios-83fa28cedf.min.js" type="text/javascript"></script>
<script src="https://csdnimg.cn/release/blogv2/dist/components/js/pc_wap_highlight-8defd55d6e.min.js" type="text/javascript"></script>
<script src="https://csdnimg.cn/release/blogv2/dist/components/js/pc_wap_common-2d7348f790.min.js" type="text/javascript"></script>
<script src="https://csdnimg.cn/release/blogv2/dist/components/js/edit_copy_code-2d3931414f.min.js" type="text/javascript"></script>
<link rel="stylesheet" href="https://csdnimg.cn/release/blog_editor_html/release1.6.12/ckeditor/plugins/codesnippet/lib/highlight/styles/atom-one-light.css">
<script src="https://g.csdnimg.cn/user-accusation/1.0.5/user-accusation.js" type="text/javascript" ></script>
<script>
 // 全局声明
 if (window.csdn === undefined) {
      window.csdn = {};
    }
    window.csdn.sideToolbar = {
        options: {
            report:{
                isShow: true,
            },
            qr: {
                isShow: false,
            },
            guide: {
                isShow: true
            }
        }
    }
    $(function(){
        $(document).on('click',"a.option-box[data-type='report']",function() {
            window.csdn.loginBox.key({
              biz: 'blog',
              subBiz: 'other_service',
              cb: function(){
                window.csdn.feedback({
                  "type":'blog',
                  "rtype":'article',
                  "rid":articleId,
                  "reportedName":username,
                  "submitOptions":{
                    "title":articleTitle,
                    "contentUrl":articleDetailUrl
                  },
                  "callback":function(){
                    showToast({
                      text: "感谢您的举报，我们会尽快审核！",
                      bottom: '10%', 
                      zindex: 9000, 
                      speed: 500,
                      time: 1500
                    })
                  }
                })
              }
            })
        });
    })
</script>
    <script src="https://g.csdnimg.cn/baidu-search/1.0.12/baidu-search.js"  type="text/javascript"></script>
<script src="https://csdnimg.cn/release/download/old_static/js/qrcode.js"></script>
<script src="https://g.csdnimg.cn/lib/qrcode/1.0.0/qrcode.min.js"></script>
<script src="https://g.csdnimg.cn/user-ordercart/3.0.1/user-ordercart.js" type="text/javascript"></script>
<script src="https://g.csdnimg.cn/user-ordertip/5.0.1/user-ordertip.js" type="text/javascript" ></script>
<script src="https://g.csdnimg.cn/order-payment/4.0.1/order-payment.js" type="text/javascript" ></script>
<script src="https://csdnimg.cn/release/blogv2/dist/pc/js/common-346b634517.min.js" type="text/javascript"></script>
<script src="https://csdnimg.cn/release/blogv2/dist/pc/js/detail-3a0c6fb7b5.min.js" type="text/javascript"></script>
<script src="https://csdnimg.cn/release/blogv2/dist/pc/js/column-3911b0dc26.min.js" type="text/javascript"></script>
<script src="https://g.csdnimg.cn/side-toolbar/3.4/side-toolbar.js" type="text/javascript"></script>
<script>
window.csdn.extensionBox = window.csdn.extensionBox ? window.csdn.extensionBox : {};
window.csdn.extensionBox.extensionBoxParams = {
    inited: function () {
    var extensionBox = document.getElementById('blogExtensionBox'); // 位置dom元素
    window.csdn.extensionBox.show({
        isdark:false, // 是否黑皮肤
        voteusername: "LinkSLA",
        posDom: extensionBox, // 插入位置 selectorString || 位置dom元素
        codyFn:()=>{
        //复制成功回调函数
            showToast({
                text: '复制成功（作者已获得对应原力分）!',
                bottom: '10%', //toast距离页面底部的距离
                zindex: 9000, //为了防止被其他控件遮盖，z-index默认为2
                speed: 500, //toast的显示速度
                time: 1500 //toast显示多久以后消失
            });
        }
    });
    }
}
</script>
<script src="https://g.csdnimg.cn/extension-box/1.1.6/extension-box.js" type="text/javascript"></script>
<script src="https://g.csdnimg.cn/copyright/1.0.4/copyright.js" type="text/javascript"></script>
<script>
    $(".MathJax").remove();
    if ($('div.markdown_views pre.prettyprint code.hljs').length > 0) {
        $('div.markdown_views')[0].className = 'markdown_views';
    }
</script>
<script type="text/javascript" src="https://csdnimg.cn/release/blog_mathjax/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
<script type="text/x-mathjax-config">
    MathJax.Hub.Config({
            "HTML-CSS": {
                    linebreaks: { automatic: true, width: "94%container" },
                    imageFont: null
            },
            tex2jax: {
                preview: "none",
                ignoreClass:"title-article"
            },
            mml2jax: {
                preview: 'none'
            }
    });
</script>
<script type="text/javascript" crossorigin src="https://g.csdnimg.cn/common/csdn-login-box/csdn-login-box.js"></script></html>
